package pl.edu.agh.gronoMining.resultAnalyzer.resultComparer.parser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import pl.edu.agh.gronoMining.frequentSubgraphFinder.frequentSearcher.subgraph.DFSCode;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.frequentSearcher.subgraph.impl.DFSCodeImpl;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.frequentSearcher.subgraph.impl.EdgeDFSComparator;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.frequentSearcher.subgraph.impl.NodesDFSComparator;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.Edge;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.Graph;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.GraphException;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.Node;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.simpleGraph.SimpleEdge;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.simpleGraph.SimpleGraph;
import pl.edu.agh.gronoMining.frequentSubgraphFinder.graph.simpleGraph.SimpleNode;

public class ToDFSParserImpl implements ToDFSParser {

	@Override
	public Map<Integer, DFSCode> parse(File graphFile) throws ParseException {
		
		Map<Integer, DFSCode> resultSet = new HashMap<Integer, DFSCode>();
		
		int lineNo = 1;
		
		try {
			BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(graphFile)));
			String line;
			Graph currentGraph = null;
			Integer currentGraphId = null;
			
			while ((line = reader.readLine()) != null) {
				
				String[] lineElements = line.trim().split(" ");
				
				if ("t".equals(lineElements[0])) {
					if (currentGraph != null) {
						DFSCode code = this.generateDFSCode(currentGraph);
						resultSet.put(currentGraphId, code);
						//System.out.println("====="+currentGraphId);
						//System.out.println(code);
					}
					currentGraphId = Integer.valueOf(lineElements[2]);
					currentGraph = new SimpleGraph();
				} else if ("v".equals(lineElements[0])) {
					
					int id = Integer.parseInt(lineElements[1]);
					int label = Integer.parseInt(lineElements[2]);
					
					Node node = new SimpleNode(id, label, 1);
					
					currentGraph.addNode(node);
					
				} else if ("e".equals(lineElements[0])) {
					
					int id1 = Integer.parseInt(lineElements[1]);
					int id2 = Integer.parseInt(lineElements[2]);
					int label = Integer.parseInt(lineElements[3]);
					Node node1 = currentGraph.getNodeById(id1);
					Node node2 = currentGraph.getNodeById(id2);
					
					Edge edge = new SimpleEdge(1, node1, node2);
					edge.checkIntegraty();
					
				} else if ("=>".equals(lineElements[0])) {
					
				} else if ("".equals(lineElements[0])) {
					
				} else {
					System.out.println(lineNo+": "+lineElements[0]);
					throw new ParseException("unknown identifier",lineNo);
				}
				lineNo++;
				
			}
			
			if (currentGraph != null) {
				DFSCode code = this.generateDFSCode(currentGraph);
				resultSet.put(currentGraphId, code);
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		} catch (GraphException e) {
			System.err.print("error in line "+lineNo);
			e.printStackTrace();
		}
		
		return resultSet;
	}
	
	private DFSCode generateDFSCode(Graph g) {
		
		Set<Edge> edgesSet = new HashSet<Edge>();
		for (Node n : g.getAllNodes()) {
			for (Edge e : n.getEdges())
				edgesSet.add(e);
		}
		DFSCode dfs = new DFSCodeImpl(edgesSet.size());
		Edge[] edgeArray = new Edge[edgesSet.size()];
	
		int i = 0;
		for (Edge e : edgesSet) {
			e.sortNodes(new NodesDFSComparator<Node>());
			edgeArray[i++] = e;
		}
		
		Arrays.sort(edgeArray, new EdgeDFSComparator<Edge>(new NodesDFSComparator<Node>()));
		
			// add all edges from array to dfs 
		dfs.createOuterToInnterMap();
		for (i = 0; i<edgeArray.length; i++)
			dfs.addEdge(edgeArray[i]);		
		dfs.removeOuterToInnterMap();

		return dfs;
	}

}
